/*
    This file is part of QTau
    Copyright (C) 2013-2018  Tobias "Tomoko" Platen <tplaten@posteo.de>
    Copyright (C) 2013       digited       <https://github.com/digited>
    Copyright (C) 2010-2013  HAL@ShurabaP  <https://github.com/haruneko>

    QTau is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    SPDX-License-Identifier: GPL-3.0+
*/

#define __devloglevel__ 4

#include "ui/dynDrawer.h"
#include "ui/Config.h"
#include "ui/noteEditor.h"

//FIXME dynamics not supported yet, need synth/storeage support

#include <QPainter>
#include <qevent.h>
#include <QPixmap>
#include "tempomap.h"
#include "assert.h"

//TODO: this class is a dummy


qtauDynLabel::qtauDynLabel(const QString &txt, QWidget *parent) : QLabel(txt, parent), _state(off) {}
qtauDynLabel::~qtauDynLabel() {}

void qtauDynLabel::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
        emit leftClicked();
    else if (event->button() == Qt::RightButton)
        emit rightClicked();
}

qtauDynLabel::EState qtauDynLabel::state() { return _state; }
void qtauDynLabel::setState(EState s)      { _state = s; }

//===========================================================================


#define SLIDE 5
#define WIDTH 10

qtauDynDrawer::qtauDynDrawer(qtauNoteEditor* qne,QWidget *parent) :
    QWidget(parent), _offset(0), _bgCache(nullptr)
{
    _editor=qne;
    connect(_editor,&qtauNoteEditor::repaintDynDrawer,this,&qtauDynDrawer::onRepaintDynDrawer);
}

qtauDynDrawer::~qtauDynDrawer()
{
    //
}

void qtauDynDrawer::onRepaintDynDrawer(void)
{
    update();
}

void qtauDynDrawer::setOffset(int off)
{
    if (off != _offset)
    {
        _offset = off;
        update();
    }
}

void qtauDynDrawer::configure(const SNoteSetup &newSetup)
{
    _ns = newSetup;
    updateCache();
    update();
}

//------------------------------------

void qtauDynDrawer::paintEvent(QPaintEvent *event)
{
    // draw bg
    int hSt         = event->rect().x() + _offset;
    _hSt = hSt;
    int barWidth    = _ns.note.width() * 4;
    int firstBar    = hSt / barWidth;
    int cacheOffset = hSt - firstBar * barWidth;

    QRect screenRect(event->rect());
    QRect cacheRect(screenRect);
    cacheRect.moveLeft(cacheRect.x() + cacheOffset);

    QPainter p(this);
    p.drawPixmap(screenRect, *_bgCache, cacheRect);


    if(_velSelected) //draw vel
    {
        _h = event->rect().height();
        foreach (quint64 key, _editor->_notes.idMap.keys())
        {
            qne::editorNote &n = _editor->_notes.idMap[key];

            double pulsesToPixels = (double)_ns.note.width() / c_midi_ppq;
            int notePos = n.pulseOffset * pulsesToPixels;

            notePos -=SLIDE;
            notePos -= hSt;

            float velocity = 100/128.0;

            if(key==_noteUnderCursor)  velocity = _velocity;

            int width = WIDTH;
            int height = _h*(1-velocity);
            QRect noteRect(notePos,_h,width,height-_h);

            if(key==_noteUnderCursor) p.fillRect(noteRect,QBrush(Qt::blue));
                else p.fillRect(noteRect,QBrush(Qt::green));
        }
    }




}

void qtauDynDrawer::resizeEvent(QResizeEvent*)
{
    updateCache();
}

//incomplete :: editing needs to be done

void qtauDynDrawer::mouseDoubleClickEvent(QMouseEvent*)
{
    //
}

void qtauDynDrawer::mouseMoveEvent(QMouseEvent* event)
{
    (void) event;
#if FIX_VOCAL_DYNAMICS
    //#FIXME this is broken
    //TODO :: move to dynDrawerHandler
    if(!(_noteUnderCursor!=))
    {
        if(event->x()>_notePos && event->x()<_notePos+WIDTH && _velSelected)
        {
            _velocity = (_h-event->y())/(1.0*_h);
        }
        update();
    }
#endif
}

void qtauDynDrawer::mousePressEvent(QMouseEvent* event)
{
    //
    if(_velSelected) //draw vel
    {
        foreach (quint64 key, _editor->_notes.idMap.keys())
        {
            qne::editorNote &n = _editor->_notes.idMap[key];           

            double pulsesToPixels = (double)_ns.note.width() / c_midi_ppq;
            int notePos = n.pulseOffset * pulsesToPixels;

            notePos -=SLIDE;
            notePos -= _hSt;

            if(event->x()>notePos && event->x()<notePos+WIDTH)
            {
                _noteUnderCursor = key;
                _notePos = notePos;
                update();
            }

            _velocity = (_h-event->y())/(1.0*_h);
        }
    }
}

void qtauDynDrawer::mouseReleaseEvent(QMouseEvent*)
{
    _noteUnderCursor = -1;
    //if(_velSelected) updateModel()

    update();
}

void qtauDynDrawer::wheelEvent(QWheelEvent *event)
{
    if (event->modifiers() & Qt::ControlModifier)
        emit zoomed(event->delta());
    else
        emit scrolled(event->delta());
}

void qtauDynDrawer::updateCache()
{
    //DEVLOG_DEBUG("updateCache()");
    if (geometry().height() == 0)
    {
        DEVLOG_ERROR("Zero height of dynDrawer in updateCache()... This definitely shouldn't happen.");
        return;
    }

    // bars fully fit in + 2 for partially visible bars
    int barWidth = _ns.note.width() * 4;
    int requiredCacheWidth = (geometry().width() / barWidth + 2) * barWidth;

    if (!_bgCache || (_bgCache->width() < requiredCacheWidth || _bgCache->height() < geometry().height()))
    {
        if (_bgCache)
            delete _bgCache;

        _bgCache = new QPixmap(requiredCacheWidth, geometry().height());
    }

    // prepare painting data
    int vSt  = 0;
    int vEnd = geometry().height();
    int mSt  = vEnd / 2 - 10;
    int mEnd = mSt + 20;

    int bar = 0;
    int beat = 0;
    int pxOff      = 0;

    QVector<QPoint> noteLines;
    QVector<QPoint> barLines;
    assert(_ns.tmap);

    while (true)
    {
        if (pxOff >= requiredCacheWidth)
            break;

        fraction time = _ns.tmap->getTimeSignatureForBar(bar);

        if (beat==time.numerator)
        {
            barLines.append(QPoint(pxOff, vSt ));
            barLines.append(QPoint(pxOff, vEnd));
            beat = 1;
            bar++;
        }
        else
        {
            noteLines.append(QPoint(pxOff, mSt ));
            noteLines.append(QPoint(pxOff, mEnd));
            beat++;
        }

        pxOff += _ns.note.width();

    }

    // paint 'em!
    _bgCache->fill(Qt::white);
    QPainter p(_bgCache);

    p.setPen(QColor(cdef_color_inner_line));
    p.drawLines(noteLines);

    p.setPen(QColor(cdef_color_outer_line));
    p.drawLines(barLines);
}
